﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Server;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.Win32;

namespace TFhisto
{
    public class CommonUIHelper : INotifyPropertyChanged
    {
        #region Constants
        internal static string ChangeSetLinkType = "Changesets";
        #endregion

        #region Fields and Class variables
        /// <summary>
        /// A reference to the selected TFS Server
        /// </summary>
        internal TfsTeamProjectCollection _tfs;

        /// <summary>
        /// A reference to the work item store for the given TFS server
        /// Used for querying the work items
        /// </summary>
        internal WorkItemStore _wis;

        /// <summary>
        /// Provides access to the individual projects
        /// </summary>
        internal ICommonStructureService _css;

        /// <summary>
        /// Used to store the images used in the treeview in memory
        /// </summary>
        private Dictionary<string, ImageSource> _graphicDictionary;

        private Dictionary<string, List<string>> _selectedBranches = new Dictionary<string, List<string>>();
        private Dictionary<string, string> _branchAssociatedToItem;
        private Dictionary<string, Dictionary<string, string>> _associatedBranchesWithItem;
        
        private Dictionary<string, Changeset[]> _mergeHistory;      // for a key "source_branch :: target_branch" a set of merged changesets 
        private Dictionary<string, List<int>> _mergeAndAddChangesets;  // for a key "source_branch :: target_branch" the list of Merge and Branch changesets  
        private Dictionary<int, Changeset[]> _cleanMergeAndAddChangesets;

        public event PropertyChangedEventHandler PropertyChanged;
        public static CommonUIHelper Helper = new CommonUIHelper();
        private DateTime _startProcessingTime;
        private bool _isProcessing = false;

        private string _filePath;
        public string FilePath
        {
            get
            {
                return _filePath;
            }
            set
            {
                _filePath = value;
            }
        }

        private string _oldfilePath;
        public string OldFilePath
        {
            get
            {
                return _oldfilePath;
            }
            set
            {
                _oldfilePath = value;
            }
        }

        private string _statusMessage;
        public string StatusMessage
        {
            get
            {
                return _statusMessage;
            }
            set
            {
                _statusMessage = value;
            }
        }

        private bool _allowQueryEdition = false;
        public bool AllowQueryEdition
        {
            get
            {
                return _allowQueryEdition;
            }
            set
            {
                _allowQueryEdition = value;
                if (Helper.PropertyChanged != null)
                {
                    Helper.PropertyChanged(Helper, new PropertyChangedEventArgs("AllowQueryEdition"));
                }
            }
        }

        /// <summary>
        /// Stores the path to icons resources
        /// </summary>
        public string IconResourcePath
        { get; set; }

        #endregion

        #region Load the graphics in the background
        internal void LoadGraphics()
        {
            BackgroundWorker backgroundWorker;

            backgroundWorker = new BackgroundWorker();
            backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_graphics_RunWorkerCompleted);
            backgroundWorker.DoWork += new DoWorkEventHandler(_graphics_DoWork);
            backgroundWorker.RunWorkerAsync();
        }

        void _graphics_DoWork(object sender, DoWorkEventArgs e)
        {
            string[] img = { "Directed Link Query.png", "Flat Query.png",
                           "Tree Query.png", "Open Folder.png", "Closed Folder.png"};
            Dictionary<string, ImageSource> d = new Dictionary<string, ImageSource>();

            for (int i = 0; i < img.Length; i++)
            {
                System.IO.Stream filestream = this.GetType().Assembly.GetManifestResourceStream(string.Format("TFhisto.Graphics.{0}", img[i]));
                PngBitmapDecoder pd = new PngBitmapDecoder(filestream, BitmapCreateOptions.None, BitmapCacheOption.Default);
                ImageSource imgSource = pd.Frames[0];
                d.Add(img[i], imgSource);
            }

            e.Result = d;
        }

        void _graphics_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            _graphicDictionary = (Dictionary<string, ImageSource>)e.Result;
        }

        #endregion

        #region Constructor and Singleton management
        CommonUIHelper()
        {
            LoadGraphics();
        }

        public static void Reset()
        {
            Helper._selectedBranches = new Dictionary<string, List<string>>();
            Helper._branchAssociatedToItem = new Dictionary<string, string>();
            Helper._associatedBranchesWithItem = new Dictionary<string, Dictionary<string, string>>();
            Helper._mergeHistory = new Dictionary<string, Changeset[]>();
            Helper._mergeAndAddChangesets = new Dictionary<string, List<int>>();
        }

        public void Initialize(TfsTeamProjectCollection collection)
        {
            CommonUIHelper.Helper._tfs = collection;
            CommonUIHelper.Helper._tfs.EnsureAuthenticated();
            CommonUIHelper.Helper._css = (ICommonStructureService)CommonUIHelper.Helper._tfs.GetService(typeof(ICommonStructureService));
            CommonUIHelper.Helper._wis = CommonUIHelper.Helper._tfs.GetService<WorkItemStore>();
        }

        public bool IsInitialized()
        {
            return CommonUIHelper.Helper._tfs != null;
        }

        #endregion
        
        #region TFS Relationship Management

        public static VersionControlServer GetVersionControlServer()
        {
            return Helper._tfs.GetService<VersionControlServer>();
        }

        public static bool CheckItem(string serverPath)
        {
            Item item = null;
            try
            {
                item = GetVersionControlServer().GetItem(serverPath);
            }
            catch (Exception) { }

            return item != null;
        }


        public static string GetServerItemForLocalItem(string localPath)
        {
            Workspace workspace = Helper._tfs.GetService<VersionControlServer>().GetWorkspace(localPath);
            return workspace.GetServerItemForLocalItem(localPath);
        }
        #endregion

        #region Branch and Changeset management

        internal static List<BranchData> GetBranches()
        {
            VersionControlServer vcs = CommonUIHelper.Helper._tfs.GetService<VersionControlServer>();

            BranchObject[] bos = vcs.QueryRootBranchObjects(RecursionType.OneLevel);

            List<BranchData> branches = new List<BranchData>();
            Array.ForEach(bos, (bo) => branches.AddRange(BrowseBranches(bo, vcs)));

            return branches;
        }

        private static int recursionlevel = 0;
        private static List<BranchData> BrowseBranches(BranchObject bo, VersionControlServer vcs)
        {
            List<BranchData> branches = new List<BranchData>();
            branches.Add(new BranchData() { Level = recursionlevel, Branch = bo });

            BranchObject[] childBranches = vcs.QueryBranchObjects(bo.Properties.RootItem, RecursionType.OneLevel);

            recursionlevel++;

            new List<BranchObject>(childBranches).FindAll(child => child.Properties.RootItem.Item != bo.Properties.RootItem.Item)
            .ForEach(child => branches.AddRange(BrowseBranches(child, vcs)));

            recursionlevel--;
            return branches;
        }

        internal static void StoreSelectedBranches(BranchObject[] selectedBranches)
        {
            List<BranchObject> selectedBranchesInList = new List<BranchObject>(selectedBranches);
            List<string> childBranches = null;
                        
            for (int i = 0; i < selectedBranches.Count(); i++)
            {
                string root = selectedBranches[i].Properties.RootItem.Item;
                childBranches = new List<string>();

                foreach (ItemIdentifier child in selectedBranches[i].ChildBranches)
                {
                    if (selectedBranchesInList.Exists(branch => branch.Properties.RootItem.Item.Equals(child.Item)))
                    {
                        childBranches.Add(child.Item);
                    }
                }
                Helper._selectedBranches.Add(root, childBranches);
            }
        }

        internal static void ReorganizeMergeDictionary()
        {
            Helper._cleanMergeAndAddChangesets = new Dictionary<int, Changeset[]>();

            List<Changeset> history;
            List<int> sortedChangesetId;

            foreach(KeyValuePair<string, List<int>> pair in Helper._mergeAndAddChangesets)
            {
                history = new List<Changeset>(Helper._mergeHistory[pair.Key]);
                int index = 0;
                sortedChangesetId = pair.Value;
                sortedChangesetId.Sort();

                foreach (int mergeId in sortedChangesetId)
                {
                    int indexOfMergeChangeset = history.IndexOf(history.Find(chgs => chgs.ChangesetId == mergeId));
                    Helper.WriteMerges(mergeId, history.GetRange(index, indexOfMergeChangeset - index + 1).ToArray());
                    index = indexOfMergeChangeset + 1;
                }
            }
        }

        private void WriteMerges(int changesetID, Changeset[] merges)
        {
            if (!_cleanMergeAndAddChangesets.Keys.Contains(changesetID))
            {
                _cleanMergeAndAddChangesets.Add(changesetID, merges);
            }
        }

        public static Changeset[] GetMerges(int ChangesetId)
        {
            Changeset[] data = null;

            if (Helper._cleanMergeAndAddChangesets.ContainsKey(ChangesetId))
            {
                data = Helper._cleanMergeAndAddChangesets[ChangesetId];
            }

            return data;
        }

        //public static Changeset[] GetMerges(int ChangesetId)
        //{
        //    string key = Helper._mergeHistory.Keys.First(x => x.Substring(x.LastIndexOf("::") + 2, x.Length - x.LastIndexOf("::") - 2).Equals(ChangesetId.ToString()));
            
        //    Changeset[] data = null;

        //    if (Helper._mergeHistory.ContainsKey(key))
        //    {
        //        data = Helper._mergeHistory[key];
        //    }

        //    return data;
        //}

        internal static bool IsItemInASelectedBranch(string item)
        {
            bool result = false;

            try
            {
                string branch = Helper._selectedBranches.Keys.First(key => item.Contains(key));
                result = true;
            }
            catch { }
            return result;
        }
        
        internal static void RegisterBranchItem(BranchHistoryTreeItem historyItem)
        {
            if (historyItem.Children.Count > 0)
            {
                foreach (BranchHistoryTreeItem branchItem in historyItem.Children)
                {
                    string fromItemPath = branchItem.Relative.BranchFromItem.ServerItem;
                    string toItemPath = branchItem.Relative.BranchToItem.ServerItem;

                    var sortedSelectedBranches = from key in Helper._selectedBranches.Keys
                                                 orderby key descending
                                                 select key;

                    string fromBranchPath = sortedSelectedBranches.FirstOrDefault(key => fromItemPath.Contains(key));
                    string toBranchPath = sortedSelectedBranches.FirstOrDefault(key => toItemPath.Contains(key));
                    Dictionary<string, string> items = null;

                    // if toBranchPath is not null (eg. the branch is selected) we register the associated item
                    if (fromBranchPath != null && fromBranchPath.Length > 0)
                    {
                        // We add the conversion entry from the item in branch to the branch itself (FROM endpoint of the relation)                        
                        if (!Helper._branchAssociatedToItem.Keys.Contains(fromItemPath))
                        {
                            Helper._branchAssociatedToItem.Add(fromItemPath, fromBranchPath);
                        }

                        // We add the relation TO >> FROM, to track Merge changetype
                        items = null;
                        if (!Helper._associatedBranchesWithItem.Keys.Contains(toItemPath))
                        {
                            items = new Dictionary<string, string>();
                            items.Add(fromBranchPath, fromItemPath);
                        }
                        else
                        {
                            items = Helper._associatedBranchesWithItem[toBranchPath];
                            Helper._associatedBranchesWithItem.Remove(toBranchPath);
                            if (!items.Keys.Contains(fromBranchPath))
                            {
                                items.Add(fromBranchPath, fromItemPath);
                            }
                        }
                        Helper._associatedBranchesWithItem.Add(toItemPath, items);

                        RegisterBranchItem(branchItem);
                    }

                    if (toBranchPath != null && toBranchPath.Length > 0)
                    {
                        // We add the conversion entry from the item in branch to the branch itself (TO endpoint of the relation)
                        if (!Helper._branchAssociatedToItem.Keys.Contains(toItemPath))
                        {
                            Helper._branchAssociatedToItem.Add(toItemPath, toBranchPath);
                        }

                        // We add the relation FROM >> TO, to track Add (and reverse Merge) changetype
                        items = null;
                        if (!Helper._associatedBranchesWithItem.Keys.Contains(fromItemPath))
                        {
                            items = new Dictionary<string, string>();
                            items.Add(toBranchPath, toItemPath);
                        }
                        else
                        {
                            items = Helper._associatedBranchesWithItem[fromItemPath];
                            Helper._associatedBranchesWithItem.Remove(fromItemPath);
                            if (!items.Keys.Contains(toBranchPath))
                            {
                                items.Add(toBranchPath, toItemPath);
                            }
                        }
                        Helper._associatedBranchesWithItem.Add(fromItemPath, items);
                    }
                }
            }
            else
            {
                string toItemPath = historyItem.Relative.BranchToItem.ServerItem;
                var sortedSelectedBranches = from key in Helper._selectedBranches.Keys
                                             orderby key descending
                                             select key;
                string toBranchPath = sortedSelectedBranches.FirstOrDefault(key => toItemPath.Contains(key));
                if (!Helper._branchAssociatedToItem.Keys.Contains(toItemPath))
                {
                    Helper._branchAssociatedToItem.Add(toItemPath, toBranchPath);
                }
            }
        }


        internal static List<string> GetRegisteredBranchItemsFromBranch(string branchItem)
        {
            List<string> branches = new List<string>();

            if (Helper._associatedBranchesWithItem.Keys.Contains(branchItem))
            {
                branches = Helper._associatedBranchesWithItem[branchItem].Values.ToList();
            }
            return branches;
        }

        public static void RegisterMergedChangesets(int changesetId, string sourcePath, string targetPath, Changeset[] changesets)
        {
            string key = sourcePath + "::" + targetPath + "::" + changesetId.ToString();
            
            int index = (new List<Changeset>(changesets).IndexOf(changesets.First(x=>x.ChangesetId==changesetId)));

            if (!Helper._mergeHistory.ContainsKey(key))
            {
                Helper._mergeHistory.Add(key, new Changeset[] { changesets[index - 1], changesets[index] });
            }
            else if (changesets[index - 1].ChangesetId > Helper._mergeHistory[key][0].ChangesetId)
            {
                Helper._mergeHistory.Remove(key);
                Helper._mergeHistory.Add(key, new Changeset[] { changesets[index - 1], changesets[index] });
            }

            if (!Helper._mergeAndAddChangesets.ContainsKey(key))
            {
                Helper._mergeAndAddChangesets.Add(key, new List<int>() { changesetId });
            }
            else if(!Helper._mergeAndAddChangesets[key].Contains(changesetId))
            {
                List<int> chgs = Helper._mergeAndAddChangesets[key];
                Helper._mergeAndAddChangesets.Remove(key);
                chgs.Add(changesetId);
                Helper._mergeAndAddChangesets.Add(key, chgs);
            }
        }

        public static string ConvertBranch(string itemPath)
        {
            return Helper._branchAssociatedToItem.FirstOrDefault(pair => pair.Key.Equals(itemPath)).Value;
        }

        public static List<string> GetRegisteredBranches()
        {
            return Helper._branchAssociatedToItem.Values.Distinct().ToList();
        }

        public static List<int> GetAllChangesetIdInMerges()
        {
            List<int> IDs = new List<int>();

            foreach (Changeset[] changesets in Helper._cleanMergeAndAddChangesets.Values)
            {
                IDs.AddRange(changesets.Select(y => y.ChangesetId).Skip(1));
            }
            return IDs.Distinct().ToList();
        }

        //public static List<int> GetAllChangesetIdInMerges()
        //{
        //    List<int> IDs = new List<int>();

        //    foreach (Changeset[] changesets in Helper._mergeHistory.Values)
        //    {
        //        IDs.AddRange(changesets.Select(y => y.ChangesetId));
        //    }
        //    return IDs.Distinct().ToList();
        //}

        /// <summary>
        /// Returns the work item that has been selected in the grid
        /// </summary>
        /// <returns>A fully populated work item object</returns>
        internal static WorkItem[] GetSelectedWorkItems(List<WorkItemData> queryResults)
        {
            List<WorkItem> wi;

            if (queryResults != null)
            {
                wi = (from w in queryResults
                      where w.Selected == true
                      select w.WI).ToList<WorkItem>();

                return wi.ToArray<WorkItem>();
            }
            else
            {
                return null;
            }
        }

        internal static BranchObject[] GetSelectedBranches(List<BranchData> queryResults)
        {
            List<BranchObject> br;

            if (queryResults != null)
            {
                br = (from b in queryResults
                      where b.Selected == true
                      select b.Branch).ToList<BranchObject>();

                BranchObject[] result = br.ToArray<BranchObject>();
                StoreSelectedBranches(result);
                return result;
            }
            else
            {
                return null;
            }
        }

        internal static List<FileChangeInfo> GetFilesByChangesetID(int changesetID)
        {
            try
            {
                List<FileChangeInfo> files = new List<FileChangeInfo>();

                VersionControlServer vcs = CommonUIHelper.Helper._tfs.GetService<VersionControlServer>();
                Changeset changeset = vcs.GetChangeset(changesetID, true, false);
                foreach (Change change in changeset.Changes)
                {
                    files.Add(new FileChangeInfo() { ChangeType = change.ChangeType.ToString(), FullPath = change.Item.ServerItem, Checked = true, Selected = true });
                }

                return files;
            }
            catch (ChangesetNotFoundException ex)
            {
                throw ex;
            }
        }

        #endregion

        #region Processing and output management

        internal static string SetOutputFileName(string defaultFileName)
        {
            SaveFileDialog save = new SaveFileDialog();
            save.Title = "Select output location";
            save.FileName = defaultFileName;
            save.AddExtension = true;
            save.Filter = "Directed Graph Markup Language (*.dgml)|*.dgml";
            save.DefaultExt = "dgml";
            save.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            save.ShowDialog();

            return save.FileName;
        }

        internal static bool IsCurrentlyProcessing()
        {
            return Helper._isProcessing;
        }

        internal static void StartProcessing(string processType)
        {
            Helper._isProcessing = true;
            Helper._startProcessingTime = DateTime.Now;
            Helper._statusMessage = "Started processing " + processType;

            if (Helper.PropertyChanged != null)
            {
                Helper.PropertyChanged(Helper, new PropertyChangedEventArgs("StatusMessage"));
            }
        }

        internal static void FinishProcessing(string processType)
        {
            Helper._isProcessing = false;
            Helper._statusMessage = "Finished processing " + processType + " in " + (DateTime.Now - Helper._startProcessingTime).TotalSeconds + " seconds";

            if (Helper.PropertyChanged != null)
            {
                Helper.PropertyChanged(Helper, new PropertyChangedEventArgs("StatusMessage"));
            }
        }

        internal static void AddFile(string filePath)
        {
            Helper._filePath = filePath;

            if (Helper.PropertyChanged != null)
            {
                Helper.PropertyChanged(Helper, new PropertyChangedEventArgs("FilePath"));
            }
        }

        internal static void ModifyFile(string oldFilePath, string newFilePath)
        {
            Helper._oldfilePath = oldFilePath;
            Helper._filePath = newFilePath;

            if (Helper.PropertyChanged != null)
            {
                Helper.PropertyChanged(Helper, new PropertyChangedEventArgs("ModifyFilePath"));
            }
        }

        #endregion

        #region Workitem management

        internal static List<TreeNode> LoadWITQueries(string SelectedTeamProjectName)
        {
            List<TreeNode> nodes = new List<TreeNode>();

            //Add a new root item
            TreeNode n = new TreeNode();
            n.Text = "Work Item Queries";
            n.Image = Helper._graphicDictionary["Closed Folder.png"];
            nodes.Add(n);

            //Loop through the top level folders in the project query folders
            foreach (QueryItem queryItem in CommonUIHelper.Helper._wis.Projects[SelectedTeamProjectName].QueryHierarchy)
            {
                //add each folder and all nodes under it recursively
                GetNodesForQueryTree(queryItem as QueryFolder, n);
            }

            return nodes;
        }

        /// <summary>
        /// Recursively load the treeview
        /// </summary>
        /// <param name="queryFolder">The Query Folder to get information about</param>
        /// <param name="node">The node to add the query folder information to</param>
        private static void GetNodesForQueryTree(QueryFolder queryFolder, TreeNode node)
        {
            //Add the folder to the treeview
            TreeNode folderNode = new TreeNode();
            folderNode.Text = queryFolder.Name;
            folderNode.Tag = queryFolder;
            folderNode.Image = Helper._graphicDictionary["Closed Folder.png"];
            node.Items.Add(folderNode);

            int lastFolder = node.Items.Count - 1;

            //Loop through all items in the list of sub-items for this folder
            foreach (QueryItem queryItem in queryFolder)
            {
                //If the item is a query folder, call this method
                if (queryItem is QueryFolder)
                {
                    GetNodesForQueryTree(queryItem as QueryFolder, node.Items[lastFolder]);
                }
                else
                {
                    try
                    {
                        //If it isn't, add the query to the list of queries
                        TreeNode itemNode = new TreeNode();

                        QueryDefinition qd = CommonUIHelper.Helper._wis.GetQueryDefinition(queryItem.Id);
                        itemNode.Text = queryItem.Name;
                        itemNode.Tag = queryItem;
                        ImageSource img = null;
                        if (qd.QueryType == QueryType.OneHop)
                        { img = Helper._graphicDictionary["Directed Link Query.png"]; }
                        else if (qd.QueryType == QueryType.List)
                        { img = Helper._graphicDictionary["Flat Query.png"]; }
                        else
                        { img = Helper._graphicDictionary["Tree Query.png"]; }

                        itemNode.Image = img;
                        folderNode.Items.Add(itemNode);
                    }
                    catch (ArgumentException ex)
                    {
                        MessageBox.Show("Could not get the query definition because of an invalid ID. Query Information is"
                            + " as follows:\nQuery Item ID:" + queryItem.Id + "\nQuery Item Name: " + queryItem.Name
                            + "\nSpecific message: " + ex.Message + "\nProcessing will continue.", "Retrieve Query Definition",
                            MessageBoxButton.OK, MessageBoxImage.Error);
                    }

                }
            }
        }

        /// <summary>
        /// Loads the link types for processing
        /// </summary>
        internal static List<TempLinkType> LoadLinkTypesForChangeset(string SelectedTeamProjectName)
        {
            List<TempLinkType> selectedLinks = new List<TempLinkType>();

            foreach (Microsoft.TeamFoundation.VersionControl.Client.ChangeType changeType in Enum.GetValues(typeof(Microsoft.TeamFoundation.VersionControl.Client.ChangeType)))
            {
                selectedLinks.Add(new TempLinkType() { LinkType = changeType.ToString(), Selected = true, Enabled = true, IsForward = true });
            }

            return selectedLinks;
        }
        
        /// <summary>
        /// Loads the link types for processing
        /// </summary>
        internal static List<TempLinkType> LoadLinkTypes(string SelectedTeamProjectName)
        {
            WorkItemLinkTypeCollection linkTypes = Helper._wis.Projects[SelectedTeamProjectName].Store.WorkItemLinkTypes;

            List<TempLinkType> selectedLinks = new List<TempLinkType>();

            foreach (WorkItemLinkType t in linkTypes)
            {
                selectedLinks.Add(new TempLinkType() { LinkType = t.ForwardEnd.Name, Selected = true, Enabled = true, IsForward = true });
                //If the link type is related then the reverse is also related
                if (t.ForwardEnd.Name != "Related")
                    selectedLinks.Add(new TempLinkType() { LinkType = t.ReverseEnd.Name, Selected = true, Enabled = true, IsForward = false });
            }

            selectedLinks.Add(new TempLinkType() { LinkType = ChangeSetLinkType, Selected = false, Enabled = true, IsForward = true });
            selectedLinks.Add(new TempLinkType() { LinkType = "Test Results", Selected = false, Enabled = true, IsForward = true });

            return selectedLinks;
        }
        
        internal static void LaunchWorkItemAnalysis(bool executeFullAnalysis,
                                                    bool chkDependencyAnalysis,
                                                    bool chkHideInterveningLinks,
                                                    bool chkShowDeletedLinks,
                                                    string SelectedTeamProjectName,
                                                    string outputFile,
                                                    List<WorkItemData> queryResults,
                                                    List<TempLinkType> selectedLinks,
                                                    string groupByFieldName)
        {
            bool useMtmLinks = ConfigurationHelper.config.UseMtmLinks;
            ProcessFullAnalysis data;

            //There is a project selected, see if they are doing full processing
            if (executeFullAnalysis)
            {
                StartProcessing("Full Analysis");
                data = new ProcessFullAnalysis(CommonUIHelper.Helper._wis, CommonUIHelper.Helper._tfs.GetService<VersionControlServer>(), SelectedTeamProjectName, outputFile, useMtmLinks);
                data.ProcessWorkItemRelationships();
                FinishProcessing("Full Analysis");
            }
            else
            {
                //No, we aren't doing a full analysis, make sure something is
                //selected to do the analysis on
                WorkItem[] selectedWorkItems = GetSelectedWorkItems(queryResults);

                if ((selectedWorkItems == null) || (selectedWorkItems.Length == 0))
                {
                    MessageBox.Show("Select one or more work items to visualize.");
                }
                else
                {
                    StartProcessing("Work Item(s) Analysis");
                    data = new ProcessFullAnalysis(CommonUIHelper.Helper._wis, CommonUIHelper.Helper._tfs.GetService<VersionControlServer>(), SelectedTeamProjectName, outputFile, useMtmLinks);

                    bool dependencyAnalysis = chkDependencyAnalysis;
                    bool hideLinks = chkHideInterveningLinks;
                    
                    data.ProcessWorkItemRelationships(selectedWorkItems, groupByFieldName, dependencyAnalysis, selectedLinks, hideLinks, chkShowDeletedLinks);

                    FinishProcessing("Work Item(s) Analysis");
                }
            }
        }

        /// <summary>
        /// Runs a given query and displays the result in the corresponding pane.
        /// </summary>
        /// <param name="query"></param>
        internal static List<WorkItemData> RunQuery(string wiql, string SelectedTeamProjectName, out Query query)
        {
            List<WorkItemData> queryResults = new List<WorkItemData>();
            WorkItemCollection wic;
            Dictionary<string, string> context = new Dictionary<string, string>();

            Mouse.OverrideCursor = Cursors.Wait;

            context.Add("project", SelectedTeamProjectName);
            context.Add("me", CommonUIHelper.Helper._wis.TeamProjectCollection.AuthorizedIdentity.DisplayName);

            query = new Query(CommonUIHelper.Helper._wis, wiql, context);

            queryResults = new List<WorkItemData>();

            if (query.IsTreeQuery || query.IsLinkQuery)
            {
                queryResults = GetHierarchicalResults(query);
            }
            else
            {
                wic = query.RunQuery();
                for (int i = 0; i < wic.Count; i++)
                {
                    queryResults.Add(new WorkItemData() { ID = wic[i].Id, WI = wic[i] });
                }
            }

            Helper.AllowQueryEdition = true;
            Mouse.OverrideCursor = null;

            return queryResults;
        }

        /// <summary>
        /// Returns all of the work items that are a result of a hierarchical query
        /// </summary>
        /// <param name="query">The query to execute</param>
        /// <returns>The list of WorkItemData that contains the results</returns>
        internal static List<WorkItemData> GetHierarchicalResults(Query query)
        {
            List<WorkItemData> temp = new List<WorkItemData>();

            //Returns the links related to this particular query - this will return
            //all of the work item ID's (source and target) returned by the qurey, but 
            //no actual work items
            WorkItemLinkInfo[] links = query.RunLinkQuery();

            //Get the actual work items associated with the source and target ID's from the
            //query
            Dictionary<int, WorkItem> resultWIs = null;
            List<WorkItemData> workItems = new List<WorkItemData>();

            //At this point, resultWIs have all of the work items in the query
            if (links != null)
                resultWIs = GetWorkItemsById(links, query);

            for (int wiIndex = 0; wiIndex < links.Length; wiIndex++)
            {
                WorkItemLinkInfo wiInfo = links[wiIndex];

                workItems.Add(new WorkItemData() { ID = wiInfo.TargetId, ParentID = wiInfo.SourceId, WI = resultWIs[wiInfo.TargetId] });
            }

            return workItems;
        }

        /// <summary>
        /// Batch retrieves work items based on the ID
        /// </summary>
        /// <param name="links">The list of work item ID's to retrieve the full work item for</param>
        /// <param name="q">The query</param>
        /// <returns>A dictionary where the key is the Work Item ID and the value is the Work Item</returns>
        internal static Dictionary<int, WorkItem> GetWorkItemsById(WorkItemLinkInfo[] links, Query q)
        {
            //Some place to store the work items and their ID's
            Dictionary<int, WorkItem> results = new Dictionary<int, WorkItem>();

            // Do batch read of work items from collected IDs
            WorkItemCollection workItems = GetWorkItemsFromLinkInfo(links, q);

            //Add the work items to the dictionary. This is necessary because when we
            //construct the layout of the results, we need to get the work items from
            //the ID's so they are ordered correctly.
            if (workItems != null)
            {
                foreach (WorkItem wi in workItems)
                    results.Add(wi.Id, wi);
            }

            return results;
        }

        /// <summary>
        /// Gets further details of the links in support of the GetWorkItemsById method
        /// </summary>
        /// <param name="links">The list of work items to get the details for</param>
        /// <param name="q">The query to execute</param>
        /// <returns>A WorkItemCollection containing all requested links</returns>
        internal static WorkItemCollection GetWorkItemsFromLinkInfo(WorkItemLinkInfo[] links, Query q)
        {
            //Check to see if there are any links to queryy
            if (links == null || links.GetLength(0) < 1)
                return null;

            //Holds the list of work item ID's to query for
            List<int> wisInBatch = new List<int>();

            // Get IDs for work items represented by post items:
            BatchReadParameterCollection batchReadParameters = new BatchReadParameterCollection();

            try
            {
                //Add all of the work item target ID's to the batch parameters for querying
                for (int wiIndex = 0; wiIndex < links.Length; ++wiIndex)
                {
                    int wiId = links[wiIndex].TargetId;
                    if (wiId != -1 && !wisInBatch.Contains(wiId))
                    {
                        batchReadParameters.Add(new BatchReadParameter(wiId));
                        wisInBatch.Add(wiId);
                    }
                }
                //Get the work item collection which contains all of the ID's
                return CommonUIHelper.Helper._wis.Query(batchReadParameters, "select [System.Id] from WorkItems");
            }
            catch
            {
                return null;
            }
        }

         internal static void LaunchChangesetAnalysis(SearchHelper searchHelper,
                                            string labelPattern,
                                            bool showFiles,
                                            bool groupFiles,
                                            bool showLabels,
                                            bool showComments,
                                            bool showWI,
                                            string SelectedTeamProjectName,
                                            string outputFile,
                                            List<FileChangeInfo> selectedFiles,
                                            List<BranchData> queryResults,
                                            List<TempLinkType> selectedLinks,
                                            string groupByFieldName)
        {
            bool useMtmLinks = ConfigurationHelper.config.UseMtmLinks;
            ProcessFullAnalysis data;

            BranchObject[] selectedBranches = GetSelectedBranches(queryResults);

            if ((selectedBranches == null) || (selectedBranches.Length == 0))
            {
                MessageBox.Show("Select one or more branches to visualize Changeset history.");
            }
            else
            {
                StartProcessing("Changeset Analysis");
                
                data = new ProcessFullAnalysis(CommonUIHelper.Helper._wis, CommonUIHelper.Helper._tfs.GetService<VersionControlServer>(), SelectedTeamProjectName, outputFile, useMtmLinks);
                data.ProcessChangesetRelationships(searchHelper, labelPattern, selectedFiles, selectedBranches, groupByFieldName, selectedLinks, showFiles, groupFiles, showLabels, showComments, showWI);

                FinishProcessing("Changeset Analysis");
            }
        }
        #endregion
    }
}
